package com.ea.common.SA;

import com.ea.common.SA.pojo.entity.DetectPersonResult;
import com.ea.common.SA.pojo.maxFaceDecte.FaceData;
import com.ea.common.SA.pojo.maxFaceDecte.FaceExpression;
import com.ea.common.SA.pojo.maxFaceDecte.FaceOcclusion;
import com.ea.common.SA.pojo.param.PersonFaceIn;
import com.ea.common.result.BizException;
import com.ea.common.result.ErrorCode;
import feign.form.FormData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class FaceRegService {
    @Resource
    FaceRegFeign faceRegFeign;

    /**
     * analyDetectPersonResult/maxFaceDetectVideo/detectPersonVideo/detectPersonPhoto
     * 上面的方法调用之前都必须使用default_company_conf先更新face_reg_sim (id=57)
     * faceRegService.sim = (double) defaultCompanyConfMapper.selectById(57).getUpperValueInt() / 100;
     */
    public double sim = 0.75;

    public int maxFaceDetectVideo(FormData video) {
        //log.info("开始检测环境");
        ResponseEntity<Result> maxFaceDetect = faceRegFeign.maxFaceDetectVideo(video);
        log.info("环境监测结果 :{}", maxFaceDetect);
        if (maxFaceDetect == null || maxFaceDetect.getStatusCode() != HttpStatus.OK ||
                maxFaceDetect.getBody() == null || maxFaceDetect.getBody().getData() == null) {
            log.error("检测环境失败");
            throw new BizException(ErrorCode.TPS_FILE_UPLOAD_VIDEO_ERROR);
        }
        try {
            FaceData faceData = parseStringToFaceData(maxFaceDetect.getBody().getData());
            //log.info("检测环境结果: {}", faceData);
            int score = getScore(faceData);
            log.info("环境监测 权重计算结果:{}", score);
            return score;
        } catch (Exception e) {
            log.error("转换环境结果失败", e);
            throw new BizException(ErrorCode.TPS_FILE_UPLOAD_VIDEO_ERROR);
        }
    }

    private int getScore(FaceData faceData) {
        // mouth_score * 10 + left_eye_score * 10 + right_eye_score * 10 + nose_score * 10 + left_eyebrow_score * 10 + right_eyebrow_score * 10
        // liveness_score * 40
        double scoreFaceOcc = faceData.getFaceOcclusion().getMouthScore() * 10
                + faceData.getFaceOcclusion().getLeftEyeScore() * 10
                + faceData.getFaceOcclusion().getRightEyeScore() * 10
                + faceData.getFaceOcclusion().getNoseScore() * 10
                + faceData.getFaceOcclusion().getLeftEyebrowScore() * 10
                + faceData.getFaceOcclusion().getRightEyebrowScore() * 10;
        double livenessScore = faceData.getLivenessScore() * 40;
        return (int) (scoreFaceOcc + livenessScore);
    }

    public FaceData parseStringToFaceData(Object getData) {
        Map<String, Object> data = (Map<String, Object>) getData;
        // rect={xmin=205.67273, ymin=210.52533, xmax=398.06143, ymax=412.54822},
        // face_angle={yaw=1.8900216, pitch=-1.9475536, roll=-4.635459},
        // blur=0.9799193, illum=6.91021E-5,
        // face_occlusion={mouth_score=0.891012, left_eye_score=0.9758405, right_eye_score=0.9445991, nose_score=0.9999912, left_eyebrow_score=0.23148412, right_eyebrow_score=0.66242075},
        // liveness_score=0.9938937,
        // face_expression={mouth_open=false, left_eye_close=false, right_eye_close=false}, faceCompletion=true}
        FaceData faceData = new FaceData();
        // Map<String, Object> rectMap = (Map<String, Object>) data.get("rect");
        // FaceRect rect = new FaceRect();
        // rect.setXmin((Double) rectMap.get("xmin"));
        // rect.setXmax((Double) rectMap.get("xmax"));
        // rect.setYmin((Double) rectMap.get("ymin"));
        // rect.setYmax((Double) rectMap.get("ymax"));
        // faceData.setFaceRect(rect);
        // Map<String, Object> faceAngleMap = (Map<String, Object>) data.get("face_angle");
        // FaceAngle faceAngle = new FaceAngle();
        // faceAngle.setYaw((Double) faceAngleMap.get("yaw"));
        // faceAngle.setPitch((Double) faceAngleMap.get("pitch"));
        // faceAngle.setRoll((Double) faceAngleMap.get("roll"));
        // faceData.setFaceAngle(faceAngle);
        faceData.setBlur(getDoubleByString(data, "blur"));
        faceData.setIllum(getDoubleByString(data, "illum"));
        Map<String, Object> faceOcclusionMap = (Map<String, Object>) data.get("face_occlusion");
        FaceOcclusion faceOcclusion = new FaceOcclusion();
        faceOcclusion.setMouthScore(getDoubleByString(faceOcclusionMap, "mouth_score"));
        faceOcclusion.setLeftEyeScore(getDoubleByString(faceOcclusionMap, "left_eye_score"));
        faceOcclusion.setRightEyeScore(getDoubleByString(faceOcclusionMap, "right_eye_score"));
        faceOcclusion.setNoseScore(getDoubleByString(faceOcclusionMap, "nose_score"));
        faceOcclusion.setLeftEyebrowScore(getDoubleByString(faceOcclusionMap, "left_eyebrow_score"));
        faceOcclusion.setRightEyebrowScore(getDoubleByString(faceOcclusionMap, "right_eyebrow_score"));
        faceData.setFaceOcclusion(faceOcclusion);
        faceData.setLivenessScore(getDoubleByString(data, "liveness_score"));
        Map<String, Object> faceExpressionMap = (Map<String, Object>) data.get("face_expression");
        FaceExpression faceExpression = new FaceExpression();
        faceExpression.setMouthOpen((Boolean) faceExpressionMap.get("mouth_open"));
        faceExpression.setLeftEyeClose((Boolean) faceExpressionMap.get("left_eye_close"));
        faceExpression.setRightEyeClose((Boolean) faceExpressionMap.get("right_eye_close"));
        faceData.setFaceExpression(faceExpression);
        faceData.setFaceCompletion((Boolean) data.get("faceCompletion"));
        return faceData;
    }

    private Double getDoubleByString(Map<String, Object> faceOcclusionMap, String mouthScore) {
        String s = faceOcclusionMap.get(mouthScore).toString();
        if (!s.contains(".")) {
            s += ".0";
        }
        return Double.valueOf(s);
    }

    private Double getDoubleByString(String s) {
        if (!s.contains(".")) {
            s += ".0";
        }
        return Double.valueOf(s);
    }

    /**
     * 检测人脸,返回人脸的用户id
     *
     * @return personId, 也就是userId
     */
    public DetectPersonResult detectPersonVideo(FormData video) {
        //log.info("开始检测人脸");
        ResponseEntity<Result> detectPersonVideo = faceRegFeign.detectPersonVideo(video);
        return analyDetectPersonResult(detectPersonVideo);
    }

    public DetectPersonResult detectPersonPhoto(FormData photo) {
        //log.info("开始检测人脸");
        ResponseEntity<Result> detectPersonPhoto = faceRegFeign.detectPerson(photo);
        return analyDetectPersonResult(detectPersonPhoto);
    }

    public void uploadFace(PersonFaceIn personFaceIn) {
        ResponseEntity<Result> resultResponseEntity = faceRegFeign.uploadFace(personFaceIn);
        //log.info("上传人脸结果：{}", resultResponseEntity);
        if (resultResponseEntity == null
                || resultResponseEntity.getStatusCode() != HttpStatus.OK
                || resultResponseEntity.getBody() == null) {
            throw new BizException(ErrorCode.TPS_FILE_UPLOAD_ERROR);
        }
        if (resultResponseEntity.getBody().getCode() != 0) {
            throw new BizException(ErrorCode.TPS_FILE_UPLOAD_ERROR);
        }
    }

    /**
     * 检测人脸,返回人脸的personFaceId
     *
     * @return personFaceId
     */
    public DetectPersonResult maxFaceDetect(FormData image) {
        //log.info("开始检测人脸");
        ResponseEntity<Result> detectPerson = faceRegFeign.detectPerson(image);
        return analyDetectPersonResult(detectPerson);
    }

    public Boolean personFaceExist(Long userId, FormData image) {
        ResponseEntity<Result> response = faceRegFeign.personFaceExist(userId, image);
        if (response == null || response.getBody() == null || response.getStatusCode() != HttpStatus.OK) {
            throw new BizException(ErrorCode.TPS_FILE_UPLOAD_ERROR);
        }
        if (response.getBody().getCode() == 1) {
            // 没有人脸
            throw new BizException(ErrorCode.TPS_FILE_UPLOAD_NO_FACE_ERROR);
        } else if (response.getBody().getCode() == 2) {
            // 人脸被识别为其他人
            throw new BizException(ErrorCode.TPS_FILE_UPLOAD_FACE_NO_CORRECT_ERROR);
        } else if (response.getBody().getCode() == 3) {
            // 未找到该人脸,也就是可以添加为备用人脸的情况
            return false;
        }
        return true;
    }

    private DetectPersonResult analyDetectPersonResult(ResponseEntity<Result> detectPersonVideo) {
        if (detectPersonVideo == null || detectPersonVideo.getBody() == null || detectPersonVideo.getStatusCode() != HttpStatus.OK) {
            throw new BizException(ErrorCode.TPS_FILE_UPLOAD_ERROR);
        }
        Map<String, Object> data = (Map<String, Object>) detectPersonVideo.getBody().getData();
        //log.info("人脸检测结果: {}", data);

        if (data == null) {
            log.info("人脸库为空，data is null");
            return null;
        } else if (Double.parseDouble((String) data.get("sim")) < sim) {
            log.info("相似度过低：{}", data.get("sim"));
            return null;
        } else {
            // 获得人脸的userId -> personId
            DetectPersonResult detectPersonResult = new DetectPersonResult();
            detectPersonResult.setPersonId((Long) data.get("personId"));
            detectPersonResult.setPersonFaceId((Long) data.get("personFaceId"));
            detectPersonResult.setPersonName((String) data.get("personName"));
            detectPersonResult.setSim(getDoubleByString((String) data.get("sim")));
            log.info("人脸检测成功，detectPersonResult: {}", detectPersonResult);
            return detectPersonResult;
        }
    }


    public static List<PersonFaceIn> convertLinkedHashMapToList(LinkedHashMap<String, Map<String, Object>> linkedHashMap) {
        List<PersonFaceIn> personFaceInList = new ArrayList<>();

        for (Map.Entry<String, Map<String, Object>> entry : linkedHashMap.entrySet()) {
            Map<String, Object> personInfo = entry.getValue();
            PersonFaceIn personFaceIn = new PersonFaceIn();
            // 设置personId
            personFaceIn.setPersonId((Long) personInfo.get("personId"));
            // 设置personFaceId
            personFaceIn.setPersonFaceId((Long) personInfo.get("personFaceId"));
            // 设置personName
            personFaceIn.setPersonName((String) personInfo.get("name"));
            personFaceInList.add(personFaceIn);
        }

        return personFaceInList;
    }

    public void removeFace(Long personFaceId) {
        try {
            ResponseEntity<Result> resultResponseEntity = faceRegFeign.removeFace(personFaceId);
            //log.info("删除人脸结果：{}", resultResponseEntity);
            if (resultResponseEntity == null
                    || resultResponseEntity.getStatusCode() != HttpStatus.OK
                    || resultResponseEntity.getBody() == null) {
                throw new BizException(ErrorCode.TPS_FILE_UPLOAD_ERROR);
            }
            //
            if (resultResponseEntity.getBody().getCode() != 0) {
                log.info("删除人脸结果：{}, code：{}", resultResponseEntity, resultResponseEntity.getBody().getCode());
                throw new BizException(ErrorCode.TPS_FILE_UPLOAD_ERROR);
            }
        } catch (Exception e) {
            log.error("删除人脸失败", e);
            throw new BizException(ErrorCode.TPS_FILE_UPLOAD_ERROR);
        }
    }

    public PersonFaceIn getFace(long personFaceId) {
        ResponseEntity<Result> resultResponseEntity = faceRegFeign.getFace(personFaceId);
        if (resultResponseEntity == null
                || resultResponseEntity.getStatusCode() != HttpStatus.OK) {
            throw new BizException(ErrorCode.TPS_FILE_UPLOAD_ERROR);
        } else if (resultResponseEntity.getBody() == null) {
            log.info("获取人脸结果：{}, code：{}", resultResponseEntity, resultResponseEntity.getBody().getCode());
            return null;
        } else if (resultResponseEntity.getBody().getCode() == 0) {
            // 把 body 转换成 PersonFaceIn
            Map<String, Object> data = (Map<String, Object>) resultResponseEntity.getBody().getData();
            PersonFaceIn personFaceIn = new PersonFaceIn();
            personFaceIn.setPersonId((Long) data.get("personId"));
            personFaceIn.setPersonFaceId((Long) data.get("personFaceId"));
            personFaceIn.setPersonName((String) data.get("personName"));
            personFaceIn.setImage((FormData) data.get("image"));
            return personFaceIn;
        }
        throw new BizException(ErrorCode.TPS_FILE_UPLOAD_ERROR);
    }

    public List<PersonFaceIn> getAllFaces() {
        ResponseEntity<Result> resultResponseEntity = faceRegFeign.getAllFaces();
        if (resultResponseEntity == null
                || resultResponseEntity.getStatusCode() != HttpStatus.OK) {
            throw new BizException(ErrorCode.TPS_FILE_UPLOAD_ERROR);
        } else if (resultResponseEntity.getBody() == null) {
            throw new BizException(ErrorCode.TPS_FILE_UPLOAD_ERROR);
        } else if (resultResponseEntity.getBody().getCode() == 0) {
            // 把 body 转换成 PersonFaceIn
            return convertLinkedHashMapToList((LinkedHashMap<String, Map<String, Object>>) resultResponseEntity.getBody().getData());
        }
        throw new BizException(ErrorCode.TPS_FILE_UPLOAD_ERROR);
    }
}
